#include "ImageProcessor.h"
#include "tools.h"
#include "source/logger.h"

#include <opencv2/opencv.hpp>

#include <QDir>
#include <QNetworkInterface>
#include <QThread>
#include <QCryptographicHash>
#include <QByteArray>
#include <QString>
#include <QtGlobal>
#include <QTime>
#include <opencv2/opencv.hpp>
#include <vector>

#include <QVariantList>
#include <QVector>
#include <QPoint>
#include <QPolygon>
#include <QRect>
#include <QPointF>
#include <QVector2D>
#include <QPolygonF>

void saveBinaryData(void* data, size_t dataSize, const std::string& baseFilename) {
    static int fileIndex =0;
    fileIndex ++ ;
    // 动态生成文件名，例如 1.npy, 2.npy ...
    std::ostringstream filenameStream;
    filenameStream << baseFilename << "_" << fileIndex << ".npy";
    std::string filename = filenameStream.str();

    std::ofstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "Failed to open file: " << filename << std::endl;
        return;
    }

    // 写入数据大小信息
    int32_t size = static_cast<int32_t>(dataSize);
    file.write(reinterpret_cast<const char*>(&size), sizeof(size));

    // 写入实际数据
    file.write(reinterpret_cast<const char*>(data), dataSize);

    file.close();
    std::cout << "Data saved to " << filename << std::endl;
}

void saveQVectorToBinary(const QVector<int8_t>& qvec, const std::string& filename) {

    std::ofstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "Failed to open file: " << filename << std::endl;
        return;
    }

    // 写入大小信息
    int32_t size = static_cast<int32_t>(qvec.size());
    file.write(reinterpret_cast<const char*>(&size), sizeof(size));

    // 写入数据
    file.write(reinterpret_cast<const char*>(qvec.data()), qvec.size() * sizeof(int8_t));
    file.close();

    std::cout << "Data saved to " << filename << std::endl;
}

bool validatePoints(const std::vector<cv::Point2f>& srcPoints, const std::vector<cv::Point2f>& dstPoints) {
    // 检查点集是否为空
    if (srcPoints.empty() || dstPoints.empty()) {
        std::cerr << "Error: One or both point sets are empty!" << std::endl;
        return false;
    }

    // 检查点的数量是否一致
    if (srcPoints.size() != dstPoints.size()) {
        std::cerr << "Error: Point sets do not have the same number of points!" << std::endl;
        return false;
    }

    // 检查点的数量是否足够
    if (srcPoints.size() < 4 || dstPoints.size() < 4) {
        std::cerr << "Error: At least 4 points are required for findHomography!" << std::endl;
        return false;
    }

    return true;
}

bool getImgInfo(const cv::Mat &frame, QList<qint16> &m_imageInfo) {
    if (frame.empty()) {
        // 处理空图像的情况
        LogError << "The input frame is empty.";
        return false;
    }

    const int WIDTH_INDEX = 0;
    const int HEIGHT_INDEX = 1;
    const int CHANNELS_INDEX = 2;

    // 确保 m_imageInfo 至少包含三个元素
    if (m_imageInfo.size() < 3) {
        m_imageInfo.clear();
        m_imageInfo << 0 << 0 << 0;
    }

    int width = frame.cols;
    int height = frame.rows;
    int channels = frame.channels();

    // 更新图像信息
    bool changed = false;
    if (m_imageInfo[WIDTH_INDEX] != width) {
        m_imageInfo[WIDTH_INDEX] = width;
        changed = true;
    }
    if (m_imageInfo[HEIGHT_INDEX] != height) {
        m_imageInfo[HEIGHT_INDEX] = height;
        changed = true;
    }
    if (m_imageInfo[CHANNELS_INDEX] != channels) {
        m_imageInfo[CHANNELS_INDEX] = channels;
        changed = true;
    }

    // 如果图像尺寸发生变化，返回 true
    return changed;
}
void adjustROIInParent(cv::Rect2d& child, const cv::Rect2d& parent) {
    // Check if child ROI is within the parent ROI
    if(parent.empty())
    {
        LogWarning << "adjustROIInParent Fail parent.empty()" ;
        return;
    }
    if(child.empty())
    {
        child = parent;
        LogWarning << "adjustROIInParent Fail child.empty()" ;
        return;
    }
    if (child.x >= parent.x &&
        child.y >= parent.y &&
        (child.x + child.width) <= (parent.x + parent.width) &&
        (child.y + child.height) <= (parent.y + parent.height)) {
        // Child ROI is within the parent ROI, no adjustment needed
        return;
    }
    LogDebug << "adjustROI ---- [" << child<< "] to "<< parent ;
    // Child ROI is not within the parent ROI, reset child ROI to parent ROI
    child = parent;
}

cv::Mat adjustBoundaryBinaryImage(const cv::Mat& binaryImg) {
    // 确保图像是二值化图像
    CV_Assert(binaryImg.type() == CV_8UC1);

    // 获取图像的第一行和最后一行
    cv::Mat topRow = binaryImg.row(0);
    cv::Mat bottomRow = binaryImg.row(binaryImg.rows - 1);

    // 计算第一行和最后一行的白色像素总和
    int topRowWhiteCount = cv::countNonZero(topRow);
    int bottomRowWhiteCount = cv::countNonZero(bottomRow);

    // 计算总的白色像素和黑色像素
    int totalWhiteCount = topRowWhiteCount + bottomRowWhiteCount;
    int totalPixelCount = binaryImg.cols * 2;
    int totalBlackCount = totalPixelCount - totalWhiteCount;

    // 如果白色像素居多，则反转图像
    if (totalWhiteCount > totalBlackCount) {
        cv::Mat invertedImg;
        cv::bitwise_not(binaryImg, invertedImg);
        return invertedImg;
    }

    // 否则返回原图像
    return binaryImg;
}

QString obfuscateMacAddress(const QString &macAddress)
{
    // 简单的字符替换和重新排列
    QString obfuscated;
    for (int i = 0; i < macAddress.size(); ++i) {
        QChar c = macAddress.at(i);
        // 将字符映射到一个范围内的其他字符
        if (c.isDigit()) {
            obfuscated.append(QChar('A' + c.digitValue())); // 将数字转为字符A-J
        } else if (c.isLetter()) {
            obfuscated.append(QChar('0' + (c.toUpper().unicode() - 'A') % 10)); // 将字母转为数字0-9
        }
    }
    // 重新排列字符
    // QString rearranged;
    // int step = 1; // 重新排列的步长
    // for (int i = 0; i < obfuscated.size(); ++i) {
    //     rearranged.append(obfuscated.at((i * step) % obfuscated.size()));
    // }
    return obfuscated ;// 截取前12个字符
}

QString getMacAddress12Chars(const QString &interfaceName, int retryCount, int retryDelayMs)
{
    for (int i = 0; i < retryCount; ++i) {
        QNetworkInterface interface = QNetworkInterface::interfaceFromName(interfaceName);

        // 检查接口是否存在且处于运行状态
        if (interface.isValid() && interface.flags().testFlag(QNetworkInterface::IsUp)) {
            QString macAddress = interface.hardwareAddress();
            if (!macAddress.isEmpty()) {
                // 去除冒号并截取前12位字符
                QString mac12Chars = macAddress.remove(':').left(12);
                // 对MAC地址进行混淆处理
                return obfuscateMacAddress(mac12Chars);
            }
        }

        // 如果接口无效或未找到有效的MAC地址，等待一段时间后重试
        QThread::msleep(retryDelayMs);
    }

    // 如果多次重试后仍然未找到有效的MAC地址，返回一个空字符串
    return QString();
}

QString getObfuscatedSerial() {
    // 读取 /proc/cpuinfo 文件
    QFile file("/proc/cpuinfo");
    QString serialNumber;

    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QString cpuInfo = file.readAll();
        file.close();

        QRegExp rx("Serial\\s+:\\s+(.*)");
        if (rx.indexIn(cpuInfo) != -1) {
            serialNumber = rx.cap(1).trimmed();
        }
    }

    // 如果未能获取到序列号，返回一个默认值或空字符串
    if (serialNumber.isEmpty()) {
        return QString("000000000000"); // 默认值
    }

    // 使用SHA-1哈希算法混淆序列号
    QByteArray hash = QCryptographicHash::hash(serialNumber.toUtf8(), QCryptographicHash::Sha1);

    // 转换为16进制字符串并取前12位
    QString obfuscatedSerial = QString(hash.toHex()).left(12);

    return obfuscatedSerial;
}


bool ensureDirectoryExists(const QString &path)
{
    QDir dir(path);
    if (!dir.exists()) {
        if (dir.mkpath(".")) {
            qDebug() << "Path created successfully:" << path;
            return true;
        } else {
            qDebug() << "Failed to create path:" << path;
            return false;
        }
    }
    return true;
}

QString customEncrypt(const QString &plainText, const QString &key) {
    // qDebug() << "PlainText:" << plainText;
    // qDebug() << "Key:" << key;
    // 首先对密钥进行哈希处理
    QByteArray hashedKey = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha256);
    // qDebug() << "Hashed Key:" << hashedKey.toHex();

    // 对输入的文本进行初步的哈希
    QByteArray initialHash = QCryptographicHash::hash(plainText.toUtf8(), QCryptographicHash::Sha256);
    // qDebug() << "Initial Hash:" << initialHash.toHex();

    // 将初步哈希值与密钥哈希结合
    QByteArray combined = initialHash;
    for (int i = 0; i < initialHash.size(); ++i) {
        combined[i] = initialHash[i] ^ hashedKey[i % hashedKey.size()];
    }
    // qDebug() << "Combined Hash:" << combined.toHex();

    // 对组合后的数据进行再次哈希处理
    QByteArray finalHash = QCryptographicHash::hash(combined, QCryptographicHash::Sha256);
    // qDebug() << "Final Hash:" << finalHash.toHex();

    // 将最终的哈希值缩短为12个字符
    QString result;
    for (int i = 0; i < 6; ++i) {
        // 将每两个字节转换为一个字符
        quint8 byte = static_cast<quint8>(finalHash[i]);
        result.append(QString::number(byte, 16).rightJustified(2, '0'));
    }
    // qDebug() << "Result before truncation:" << result;

    // 确保结果为12位
    result = result.left(12);
    // qDebug() << "Final Result:" << result.toUpper();  // 转换为大写的12位字符串

    return result.toUpper();
}

void drawDashedRectangle(cv::Mat &image, int x, int y, int width, int height, int cls) {
    cv::Scalar color;

    // 根据 cls 设置颜色
    switch (cls) {
    // case 0: color = cv::Scalar(0, 255, 0); break; // 绿色
    // case 1: color = cv::Scalar(0, 0, 255); break; // 红色
    // 其他 cls 的颜色设置
    default: color = cv::Scalar(0, 255, 235); break; // 蓝色
    }

    int lineType = cv::LINE_4;
    int thickness = 1;

    // 绘制虚线矩形
    cv::rectangle(image, cv::Point(x, y), cv::Point(x + width, y + height), color, thickness, lineType,0);
}

double calculateStraightness(const std::vector<cv::Point>& points, const cv::Vec4f& line, cv::Point &maxAbovePoint, cv::Point &maxBelowPoint) {
    double normFactor = std::sqrt(line[0] * line[0] + line[1] * line[1]);
    double maxAbove = 0;
    double maxBelow = 0;

    for (const auto& pt : points) {
        // 计算点到直线的垂直距离（带归一化）
        double distance = (line[1] * (pt.x - line[2]) - line[0] * (pt.y - line[3])) / normFactor;

        if (distance > maxAbove) {
            maxAbove = distance;
            maxAbovePoint = pt;
        }
        if (distance < maxBelow) {
            maxBelow = distance;
            maxBelowPoint = pt;
        }
    }

    double distanceSum = std::abs(maxAbove) + std::abs(maxBelow);
    return distanceSum;
}



cv::Mat rotateImageByFitLine(const cv::Mat& image, const cv::Vec4f& fitLine)
{
    // 计算旋转角度（以度为单位）
    double angle = std::atan2(fitLine[1], fitLine[0]) * 180.0 / CV_PI;

    // 获取图像中心点
    cv::Point2f center(image.cols / 2.0f, image.rows / 2.0f);

    // 为了减少黑边，增加边界（具体大小可以根据实际情况调整）
    int border = static_cast<int>(std::max(image.cols, image.rows) * 0.2);

    // 扩展图像边界，使用反射填充（或其他方式）
    cv::Mat paddedImage;
    cv::copyMakeBorder(image, paddedImage, border, border, border, border, cv::BORDER_REPLICATE);

    // 更新图像中心点（相对于扩展后的图像）
    center = cv::Point2f(paddedImage.cols / 2.0f, paddedImage.rows / 2.0f);

    // 生成旋转矩阵
    cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, angle, 1.0);

    // 旋转图像
    cv::Mat rotatedImage;
    cv::warpAffine(paddedImage, rotatedImage, rotationMatrix, paddedImage.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));

    // 裁剪回原始图像大小
    cv::Rect roi(border, border, image.cols, image.rows);
    cv::Mat croppedImage = rotatedImage(roi);

    // 返回裁剪后的图像
    return croppedImage;
}

double calculateGradientDifference(const cv::Mat& line1, const cv::Mat& line2) {
    // 简单计算梯度差异的绝对值和
    // return cv::sum(cv::abs(line1 - line2))[0];

    cv::Mat diff = cv::abs(line1 - line2);

    // 找到最大差异值
    double maxVal;
    cv::minMaxLoc(diff, nullptr, &maxVal);

    return maxVal;
}

void drawROIByQList(cv::Mat& drawImage, const QVariantList& lenthROI) {
    if (lenthROI.size() != 4) {
        //qWarning() << "lenthROI must contain 4 elements (x, y, width, height)";
        return;
    }

    int x = lenthROI[0].toInt();
    int y = lenthROI[1].toInt();
    int width = lenthROI[2].toInt();
    int height = lenthROI[3].toInt();

    // 绘制矩形框
    cv::rectangle(drawImage, cv::Rect(x, y, width, height), cv::Scalar(0, 255, 0), 2); // 绿色边框，线宽为2

    int centerY = y + height / 2;

    // 绘制与图像等宽的水平直线
    cv::line(drawImage, cv::Point(0, centerY), cv::Point(drawImage.cols, centerY), cv::Scalar(255, 0, 0), 2); // 红色直线，线宽为1
}


int findLineDistanceV2(const cv::Mat& image,
                       QVariantList lenthROI,
                       double threshold, double thresholdR,
                       int& leftX, int& rightX,
                       int countThrethon, int isShow)
{
    cv::Mat middleRegion;
    int startX = 0;

    // 提取ROI区域或中间区域
    if (lenthROI.size() != 4) {
        int height = image.rows;
        int startY = height * 0.35;
        int endY = height * 0.65;
        middleRegion = image(cv::Range(startY, endY), cv::Range::all()).clone();
    } else {
        int x = lenthROI[0].toInt();
        int y = lenthROI[1].toInt();
        int widthROI = lenthROI[2].toInt();
        int heightROI = lenthROI[3].toInt();
        startX = x;
        cv::Rect roi(x, y, widthROI, heightROI);

        if (roi.x >= 0 && roi.y >= 0 && roi.x + roi.width <= image.cols && roi.y + roi.height <= image.rows) {
            // ROI 在图像内，继续处理
            middleRegion = image(roi).clone();
        } else {
            int height = image.rows;
            int startY = height * 0.35;
            int endY = height * 0.65;
            middleRegion = image(cv::Range(startY, endY), cv::Range::all()).clone();
        }



    }

    // 直方图均衡
    //cv::equalizeHist(middleRegion, middleRegion);

    // 二值化并过滤噪声区域
    cv::Mat binaryImageL, binaryImageR;
    cv::threshold(middleRegion, binaryImageL, threshold, 255, cv::THRESH_BINARY);

    // 检查左侧第一列是否需要反向
    bool shouldInvertL = (cv::countNonZero(binaryImageL.col(0)) > binaryImageL.rows / 2);
    if (shouldInvertL) {
        cv::bitwise_not(binaryImageL, binaryImageL);
    }

    // 过滤掉小于冗余像素数量的区域
    std::vector<std::vector<cv::Point>> contoursL;
    cv::findContours(binaryImageL, contoursL, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    for (const auto& contour : contoursL) {
        if (cv::contourArea(contour) < countThrethon) {
            cv::drawContours(binaryImageL, std::vector<std::vector<cv::Point>>{contour}, -1, cv::Scalar(0), cv::FILLED);
        }
    }

    // 从左到右找到第一个前景列
    for (int x = 0; x < binaryImageL.cols; ++x) {
        int nonZeroCount = cv::countNonZero(binaryImageL.col(x));
        if (nonZeroCount > 0) {
            leftX = x;
            break;
        }
    }

    // 右侧二值化和过滤
    cv::threshold(middleRegion, binaryImageR, thresholdR, 255, cv::THRESH_BINARY);
    bool shouldInvertR = (cv::countNonZero(binaryImageR.col(binaryImageR.cols - 1)) > binaryImageR.rows / 2);
    if (shouldInvertR) {
        cv::bitwise_not(binaryImageR, binaryImageR);
    }

    // 过滤掉小于冗余像素数量的区域
    std::vector<std::vector<cv::Point>> contoursR;
    cv::findContours(binaryImageR, contoursR, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    for (const auto& contour : contoursR) {
        if (cv::contourArea(contour) < countThrethon) {
            cv::drawContours(binaryImageR, std::vector<std::vector<cv::Point>>{contour}, -1, cv::Scalar(0), cv::FILLED);
        }
    }

    // 从右到左找到第一个前景列
    for (int x = binaryImageR.cols - 1; x > 0; --x) {
        int nonZeroCount = cv::countNonZero(binaryImageR.col(x));
        if (nonZeroCount > 0) {
            rightX = x;
            break;
        }
    }

    // 可选：显示图像和绘制结果
    if (isShow && ImageProcessor::getInstance().selectedStep() == ImageProcessor::MeauCv) {
        ImageProcessor::getInstance().setcaptureImgMode(ImageProcessor::CapPause);
        ImageProvider::getInstance().image2qml(middleRegion, "Box1");

        cv::Mat colorBinaryImage;
        if (isShow == 1) {
            cv::cvtColor(binaryImageL, colorBinaryImage, cv::COLOR_GRAY2BGR);
            cv::line(colorBinaryImage, cv::Point(leftX, 0), cv::Point(leftX, colorBinaryImage.rows - 1), cv::Scalar(0, 0, 255), 2);
        } else if (isShow == 2) {
            cv::cvtColor(binaryImageR, colorBinaryImage, cv::COLOR_GRAY2BGR);
            cv::line(colorBinaryImage, cv::Point(rightX, 0), cv::Point(rightX, colorBinaryImage.rows - 1), cv::Scalar(0, 0, 255), 2);
        }
        ImageProvider::getInstance().image2qml(colorBinaryImage, "Main");
    }

    leftX += startX;
    rightX += startX;

    // 计算竖线之间的X距离
    int distance = rightX - leftX;

    return distance;
}


int findLineDistance(const cv::Mat& image,
                     QVariantList lenthROI ,
                     double threshold,double thresholdR, int&leftX,
                     int&rightX , int countThrethon) {
    cv::Mat middleRegion;
    int startX = 0;
    if(lenthROI.size() != 4)
    {
        int height = image.rows;
        int width = image.cols;
        // 计算中间30%的区域
        int startY = height * 0.35;
        int endY = height * 0.65;

        // 提取中间30%区域
        middleRegion = image(cv::Range(startY, endY), cv::Range::all()).clone();
    }else
    {
        int x = lenthROI[0].toInt();
        int y = lenthROI[1].toInt();
        int widthROI = lenthROI[2].toInt();
        int heightROI = lenthROI[3].toInt();
        startX = x;
        cv::Rect roi(x, y, widthROI, heightROI);
        middleRegion = image(roi).clone();
    }

    //cv::equalizeHist(middleRegion, middleRegion);
    // 计算X方向的梯度
    // cv::Mat gradientX;
    // cv::Sobel(middleRegion, gradientX, CV_64F, 1, 0, 3);
    cv::Mat leftCol = middleRegion.col(0);
    cv::Mat rightCol = middleRegion.col(middleRegion.cols - 1);
    bool isServon = false;
    int leftAboveThreshold = countPixelsAboveThreshold(leftCol, threshold);
    int leftBelowThreshold = leftCol.rows - leftAboveThreshold;
    if (leftAboveThreshold > leftBelowThreshold)
    {
        isServon = true;
    }
    leftX = 0;
    rightX = middleRegion.cols - 1;

    // double initialLeftGradient ;
    // double initialRightGradient ;

    bool leftStop = false;
    bool rightStop = false;

    while (leftX < rightX - 1) {
        if (!leftStop) {
            leftX++;
            // 使用 colRange 获取矩阵的特定列范围
            cv::Mat leftCol = middleRegion.colRange(leftX, leftX + 1);
            // cv::minMaxLoc(leftCol, nullptr, &initialLeftGradient);
            // if (std::abs(initialLeftGradient) > threshold) {
            //     leftStop = true;
            // }
            if(countPixelsAboveThreshold(leftCol,threshold , isServon) >countThrethon)
            {
                leftStop = true;
            }
        }

        if (!rightStop) {
            rightX--;
            // 使用 colRange 获取矩阵的特定列范围
            cv::Mat rightCol = middleRegion.colRange(rightX, rightX+1);
            // cv::minMaxLoc(rightCol, nullptr, &initialRightGradient);
            // if (std::abs(initialRightGradient) > threshold) {
            //     rightStop = true;
            // }
            if(countPixelsAboveThreshold(rightCol,thresholdR , isServon) > countThrethon)
            {
                rightStop = true;
            }
        }

        // 如果两边都停止了，则跳出循环
        if (leftStop && rightStop) {
            break;
        }
    }
    leftX += startX;
    rightX += startX;
    // 计算竖线之间的X距离
    int distance = rightX - leftX;
    return distance;
}

void drawLinesOnImage(cv::Mat& image, int leftX, int rightX) {
    int height = image.rows;

    // 画左侧竖线
    cv::line(image, cv::Point(leftX, 0), cv::Point(leftX, height), cv::Scalar(134, 255, 0), 2);

    // 画右侧竖线
    cv::line(image, cv::Point(rightX, 0), cv::Point(rightX, height), cv::Scalar(255, 168, 0), 2);
}

void drawHelperLinesOnImage(cv::Mat& image, double leftX, double rightX) {
    int height = image.rows;

    // 四舍五入得到整数
    int roundedLeftX = static_cast<int>(std::round(leftX));
    int roundedRightX = static_cast<int>(std::round(rightX));

    // 画最大
    cv::line(image, cv::Point(roundedLeftX, 0), cv::Point(roundedLeftX, height), cv::Scalar(134, 255, 0), 2);

    // 画最小
    cv::line(image, cv::Point(roundedRightX, 0), cv::Point(roundedRightX, height), cv::Scalar(0, 255, 253), 2);
}

double fitAngleLimited(const cv::Mat& binaryImg) {
    std::vector<cv::Point2f> points;
    for (int y = 0; y < binaryImg.rows; ++y) {
        for (int x = 0; x < binaryImg.cols; ++x) {
            if (binaryImg.at<uchar>(y, x) > 0) { // 假设前景为白色 (255)
                points.emplace_back(static_cast<float>(x), static_cast<float>(y));
            }
        }
    }

    cv::Vec4f line;
    if (points.size() >= 2) {
        // 确保有足够的点进行拟合
        try {
            cv::fitLine(points, line, cv::DIST_L2, 0, 0.01, 0.01);
        } catch (const cv::Exception& e) {
            qWarning() << "OpenCV exception: " << e.what() ;
            return 0;
            // 处理异常，可以选择退出或者提供默认的拟合结果
        }
    } else {
        qWarning() << "Not enough points to fit a line." ;
        return 0;
        // 可以选择返回一个默认的值或者采取其他措施
    }

    // 提取方向向量
    double vx = line[0];
    double vy = line[1];

    // 计算角度
    double angle = atan2(vy, vx) * 180.0 / CV_PI;

    // 将角度限制在 -45 到 45 度之间
    if (angle > 45) {
        angle -= 90;
    } else if (angle < -45) {
        angle += 90;
    }

    return angle;
#if 0
    // 提取前景像素的坐标


    if (points.empty()) {
        throw std::runtime_error("No foreground pixels found in the image.");
    }

    // 使用PCA计算主轴方向
    cv::PCA pca(cv::Mat(points).reshape(1), cv::Mat(), cv::PCA::DATA_AS_ROW);

    // 获取主成分方向的角度
    cv::Mat eigenvectors = pca.eigenvectors;
    cv::Point2f eigenvector(eigenvectors.at<float>(0, 0), eigenvectors.at<float>(0, 1));
    double angle = atan2(eigenvector.y, eigenvector.x) * 180.0 / CV_PI;

    // 将角度限制在 -45 到 45 度之间
    if (angle > 45) {
        angle -= 90;
    } else if (angle < -45) {
        angle += 90;
    }

    return angle;
#endif
}

bool areaisClosed(const QVector<QPointF> &points) {
    if (points.size() < 2) return false;
    QPointF first = points.first();
    QPointF last = points.last();
    return first == last;
}

// 获取凸包
QPolygonF areaconvexHull(const QVector<QPointF> &points) {
    QPolygonF hull;
    // 使用Qt的QPolygonF::toPolygon方法获取凸包
    QPolygonF poly(points);
    hull = poly.toPolygon();
    return hull;
}

// 判断矩形是否在包围框中
bool areaisRectangleInBounding(const QPolygonF &boundingPolygon, const QRect &rect) {
    QVector<QPointF> rectPoints;
    rectPoints << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft();

    for (const auto &point : rectPoints) {
        if (!boundingPolygon.containsPoint(point, Qt::OddEvenFill)) {
            return false;
        }
    }
    return true;
}

bool isRectangleInPolygon(const QPolygonF &polygon, int left, int top, int right, int bottom) {
    // 构造矩形的四个角点
    QPointF topLeft(left, top);
    QPointF topRight(right, top);
    QPointF bottomLeft(left, bottom);
    QPointF bottomRight(right, bottom);

    // 判断矩形的每个角点是否都在 QPolygonF 区域内
    if (polygon.containsPoint(topLeft, Qt::OddEvenFill) &&
        polygon.containsPoint(topRight, Qt::OddEvenFill) &&
        polygon.containsPoint(bottomLeft, Qt::OddEvenFill) &&
        polygon.containsPoint(bottomRight, Qt::OddEvenFill)) {
        return true;
    } else {
        return false;
    }
}

std::vector<cv::Point> convertQPolygonFToCvPoints(const QPolygonF &polygon) {
    std::vector<cv::Point> cvPoints;
    for (const QPointF &point : polygon) {
        cvPoints.push_back(cv::Point(static_cast<int>(point.x()), static_cast<int>(point.y())));
    }
    return cvPoints;
}

// 在图像中绘制 QList<QPolygonF>
void drawPolygonsOnImage(cv::Mat &image, const QList<QPolygonF> &polygons) {
    //qDebug() << "polygons" << polygons.size();
    for (const QPolygonF &polygon : polygons) {
        std::vector<cv::Point> cvPoints = convertQPolygonFToCvPoints(polygon);
        //qDebug() << "cvPoints" << cvPoints.size();
        // 绘制多边形
        cv::polylines(image, cvPoints, true, cv::Scalar(0, 255, 0), 2);  // 绿色线条，宽度为2
    }
}

int countPixelsAboveThreshold(const cv::Mat& mat, double threshold, bool isServon) {
    // 确保输入矩阵是单通道
    if (mat.channels() != 1) {
        throw std::invalid_argument("Input matrix must be single-channel.");
    }

    // 计算绝对值矩阵
    cv::Mat absMat;
    cv::absdiff(mat, cv::Scalar(0), absMat);

    // 创建一个二值掩码，满足条件的像素点为 1，不满足的为 0
    cv::Mat mask ;
    if(isServon )
    {
        mask = absMat < threshold;
    }
    else {
        mask = absMat > threshold;
    }


    // 计算满足条件的像素数量
    int count = cv::countNonZero(mask);

    return count;
}

bool containsInt(const QVariantList &list, int value)
{
    for (const QVariant &item : list) {
        if (item.type() == QVariant::Int && item.toInt() == value) {
            return true;
        }
    }
    return false;
}
